package lumis.portal.audit;

import java.util.ArrayList;
import java.util.List;

/**
 * Represents the Audit context. It holds the current audit entry and the
 * parent context (the audit context that originated the current context).
 * 
 * @version $Revision: 13093 $ $Date: 2011-05-28 18:40:18 -0300 (Sat, 28 May 2011) $
 * @since 6.0.0
 */
class AuditContext implements Cloneable
{
	/**
	 * Hold the current context.
	 * @since 6.0.0
	 */
	private static InheritableThreadLocal<AuditContext> currentContext = new InheritableThreadLocal<AuditContext>()
	{
		@Override
		protected AuditContext childValue(AuditContext parentValue)
		{	
			if (parentValue != null)
			{
				AuditContext auditContext = parentValue.clone();
				auditContext.setDifferentThread(true);
				return auditContext;
			}
			else
			{
				return null;
			}
		}
	};

	/**
	 * The {@link AuditEntry} instance for this AuditContext.
	 * @since 6.0.0
	 */
	private AuditEntry entry;
	
	/**
	 * The {@link AuditContext} instance representing the parent context.
	 * @since 6.0.0 
	 */
	private AuditContext parent;
	
	/**
	 * The list of child contexts of this context.
	 * @since 6.0.0
	 */
	private List<AuditContext> childList = new ArrayList<AuditContext>();
	
	/**
	 * Indicate if the child entries must be registered in database or only in
	 * log. 
	 * @since 6.0.0
	 */
	private boolean registerChilds = true;	

	/**
	 * True if the context was cloned during a thread fork.
	 * @since 6.0.0
	 */
	private boolean differentThread = false;
	
	/**
	 * Holds a parent context that belongs to another thread. It means that
	 * another context in a different thread originated the current context. If
	 * the current context doesn't has a direct parent, the contextParentThread
	 * will be used to hold the parent in the database.
	 * @since 6.0.0
	 */
	private AuditContext contextParentThread;
		
	/**
	 * Retrieve the current context for the current thread. 
	 * @return	an instance of AuditContext that represents the current
	 * 			context.
	 * @since 6.0.0
	 */
	protected static AuditContext getCurrentContext()
	{
		return currentContext.get();
	}
	
	/**
	 * Sets the current context for the current thread.
	 * @param context	an instance of AuditContext.
	 * @since 6.0.0
	 */
	protected static void setCurrentContext(AuditContext context)
	{
		currentContext.set(context);
	}
	
	protected AuditContext()
	{
		
	}
	
	protected void setEntry(AuditEntry entry)
	{
		this.entry = entry;
	}
	
	protected AuditEntry getEntry()
	{
		return this.entry;
	}
	
	protected AuditContext getParent()
	{
		return this.parent;
	}
	
	protected void setParent(AuditContext parent)
	{
		this.parent = parent;
	}
	
	/**
	 * Add a child context for this context.
	 * @param child	the {@link AuditContext} instance representing the child.
	 * @since 6.0.0
	 */
	protected void addChild(AuditContext child)
	{		
		this.childList.add(child);
		child.setParent(this);
	}
	
	protected List<AuditContext> getChildList()
	{
		return this.childList;
	}
	
	protected AuditContext getContextParentThread()
	{
		return contextParentThread;
	}

	protected void setContextParentThread(AuditContext contextParentThread)
	{
		this.contextParentThread = contextParentThread;
	}
	
	protected boolean isDifferentThread()
	{
		return differentThread;
	}

	protected void setDifferentThread(boolean differentThread)
	{
		this.differentThread = differentThread;
	}

	protected boolean isRegisterChilds()
	{
		return registerChilds;
	}

	protected void setRegisterChilds(boolean registerChilds)
	{
		this.registerChilds = registerChilds;
	}
	
	/**
	 * Clears the {@link Thread thread} data.
	 * 
	 * @since 6.0.0
	 */
	static void clearThreadData()
	{
		currentContext.remove();
	}

	@Override
	protected AuditContext clone()	
	{
		try
		{
			AuditContext auditContext = (AuditContext) super.clone();
			// TODO Auto-generated method stub
			return auditContext;
		}
		catch (CloneNotSupportedException e)
		{
			// TODO
			throw new RuntimeException(e);
		}
	}
}